<?php
/**
 * Data Table 
 * Componente de renderização de DataGrids
 * @author benrainir
 * @see http://www.datatables.net
 */
class TDataTable 
{ 
    /**
     * Model
     * @var object
     */
    private $model;
    
     /**
     * Metodo
     * @var string
     */
    private $metodo;
    
    /**
     * Criteria
     * @var array
     */
    private $criteria;
    
    /**
     * Page Atual
     * @var object
     */
    private $page;
    
    /**
     * Html
     * @access private
     * @var string
     */
    private $html;
    
    /**
     * isPaginate
     * @var bool
     */
    private $isPaginate = TRUE;    
    	
    /**
     * Columns 
     * @var array
     */
	private $columns = array();	
	
	/**
	 * Data
	 * @var array
	 */
	private $data = array();

	/**
	 * Key Column
	 * @var array
	 */
	private $keyColumn = array();
	
	/**
	 * Indica se havera pesquisa no grid
	 * @var bool
	 */
	private $seachGrid = TRUE;
	
	/**
	 * Indica se havera footer no grid
	 * @var bool
	 */
	private $footer = TRUE;
	
	/**
	 * Data Filters
	 * Criterio de filtragem (pesquisa) de cada campo
	 * @var array
	 */
	private $dataFilters = array();
			
	/**
	 * Mensagem que aparece quando a consulta não retorna nenhum resultado.
	 * @var string
	 */
	private $emptyMsg;
	
	private $itens_per_page;
	
	/**
	 * Construtor
	 * @param $model
	 * @param $key
	 * @param $criteria
	 * @param $options
	 * @param $columns
	 * @param $metodo
	 */
	public function __construct($model, $key, $criteria = array(), $options = array(), $columns = array(), $metodo='listar')
	{
	    $checkColumn        = ( isset($options['checkColumn']) )      ? $options['checkColumn']     : TRUE;
	    $radioColumn        = ( isset($options['radioColumn']) )      ? $options['radioColumn']     : FALSE;
	    $editColumnAction   = ( isset($options['editColumn']) )       ? $options['editColumn']      : TRUE;
	    $tituloColumnAction = ( isset($options['editHeader']) )       ? $options['editHeader']      : 'Editar';
        $linkColumnAction   = ( isset($options['editLink']) )         ? $options['editLink']        : $this->linkColumnActionDefault();
        $classColumnAction  = ( isset($options['editClass']) )        ? $options['editClass']       : 'editar';
        $atributoHtml       = ( isset($options['htmlInputColumn']) )  ? $options['htmlInputColumn'] : '';	      
        $seachGrid          = ( isset($options['searchGrid']) )       ? $options['searchGrid']       : TRUE;
        $footer             = ( isset($options['footer']) )           ? $options['footer']          : TRUE;
        $emptyMsg           = ( isset($options['emptyMsg']) )         ? $options['emptyMsg']        : $this->getDefaultEmptyMsg();
        $editTarget         = ( isset($options['editTarget']) )       ? $options['editTarget']      : '';
	    $itensPerPage       = ( isset($options['itensPerPage']) )     ? $options['itensPerPage']      : 10;
        
        $this->emptyMsg = $emptyMsg;
        $this->footer = $footer;
        $this->model = $model;
	    $this->metodo = $metodo;
	    $this->seachGrid = $seachGrid;
	    $this->itens_per_page = $itensPerPage;
	    $this->criteria = $criteria;
	   	   
	    if(is_string($key)){
	        $this->keyColumn[] = $key;
	    }
	    if(is_array($key)){
	        $this->keyColumn = $key;
	    }	    
	    
	    if($checkColumn){
	        $this->addCheckColumn($atributoHtml);
	    }
	    if($radioColumn){
	        $this->addRadioColumn($atributoHtml);
	    }	    
	    $this->addManyColumns($columns);
	    if($editColumnAction){
	        $col = new TDataTableColumn($tituloColumnAction,TDataTableColumn::COLUMN_TYPE_ACTION,$tituloColumnAction);
	        $col->setClass($classColumnAction);
	        $col->setLink($linkColumnAction);
	        $col->setTarget($editTarget);
	        $this->columns[] = $col;
	    }	    
	    
	}

	
	/**
	 * Render
	 */
	public function render()
	{
	    $this->loadData($this->model, $this->criteria);
	    $this->loadPageNumber();
	    $this->html  = $this->renderToolBar();
	    $this->html .= '<div class="gridPanel">';
	    $this->html .= '<table class="grid" cellspacing="1">';
	    $this->html .= '<thead>';
	    $this->html .= $this->renderHeader();
	    $this->html .= $this->renderFilter();
	    $this->html .= '</thead>';	    
	    $this->html .= $this->renderBody();
	    $this->html .= $this->renderFooter();
	    $this->html .= '</table>';
	    $this->html .= '</div>';
	    return $this->html;
	}
	

	/**	 
	 * Render ToolBar
	 */
	private function renderToolBar()
	{
	    $html  = '';
	    if ($this->seachGrid){
	        $html .= '<input name="btnAcao" type="submit" value="Pesquisar" class="pesquisar default cancel" /> ';
	    }	    
	    return $html;
	}
	

	/**
	 * Render Header
	 */
    private function renderHeader()
	{
	    $html = "<tr>";
        foreach($this->getColumns() as $col){
           $html .= $col->renderHeader();        
        }       
        $html .= "</tr>";	     
        return $html;
	}
	
	
	/**
	 * Render Filter
	 */
    private function renderFilter()
	{
	    $totalItens = $this->numItens() ;
	    $html = '';	        	    
	    if ($this->seachGrid){
    	    $dat = $this->data;
    	    $html = "<tr>";
            foreach($this->getColumns() as $col){
               $html .= $col->renderFilter($this->data);        
            }       
            $html .= "</tr>";
	    }	    	     
        return $html;
	}
	

	/**
	 * Render Body
	 */
    private function renderBody()
	{
	    $totalItens = $this->numItens() ;
	    $primeiroItem = $this->firstItemIndex();
        $ultimoItem = $this->lastItemIndex(); 
        $html = '';
        if ($totalItens >0){
            $html = '<tbody>';
            for($i= $primeiroItem; $i < $ultimoItem ; $i++) 
            {
                $odd = ( $i % 2 != 0 ) ? 'class="odd"' : false; 
                $html .= "<tr $odd>";
                $registro = pg_fetch_array($this->data, $i);
                foreach($this->getColumns() as $col){
                    $html.= $col->renderBody($registro,$this->keyColumn);
                }
                 $html.='</tr>';        
            }        
            $html .= '</tbody>';
        }
        else{
            $html = '<tbody><tr><td colspan="'.$this->numColumns().'">';
            $html .= $this->emptyMsg;
            $html .= '</td></tr></tbody>';
        }	     
        return $html;
	}
	

	/**
	 * Render Footer
	 */
	private function renderFooter()
	{
	    $html = '';
	    if($this->footer){
    	    $pagina = $this->page;
    	    $totalItens = $this->numItens() ; 
    	    $primeiroItem = $this->firstItemIndex();
            $ultimoItem = $this->lastItemIndex();
    
    	    #Codigo de Pesquisa referente a ação do botao pesquisar
        	$formPesquisa = array();
        	$urlPesquisa = '';    	     	    
    	    foreach ($this->dataFilters as $fil){
                $urlPesquisa .= '&fil_'.$fil['campo'].'='.urlencode($fil['valor']);                            
            }   
    	    
            $html = '<tfoot>';	            
            $html .= '<tr>';
            $html .= '<td colspan="'.$this->numColumns().'">';
            $primeiroExibindo = ( $this->numItens() > 0 ) ? $primeiroItem + 1 : 0;
            $html .= "Exibindo de " . ( $primeiroExibindo ) . " à $ultimoItem de $totalItens registros.";
            $html .= "</td>";
            $html .= "</tr>";
            
            
            if ($this->isPaginate and ($this->numItens() > $this->itens_per_page )){
                $url = $_SERVER['REQUEST_URI'];
    	        $separator = ( strpos ( $url, '?' ) > -1 && strpos ( $url, '?pagina=' ) == 0 ) ? '&' : '?';
    	        if ( strpos ( $url, 'pagina=' ) > -1 )
                    $url = substr( $url, 0, strpos( $url, 'pagina=' ) - 1 );
    	             	
    	         $html .= "<tr class='paginacao'>";	
    	         $html .= "<td colspan='".$this->numColumns()."'>";
    	                   		
                // Primeira Página da Lista
                $primeiraPagina = ( $pagina > 2 ) ? $pagina - 2 : 1;
                
                // Total de Páginas da Lista
                $totalPaginas = floor( $totalItens / $this->itens_per_page );
                if ( $totalItens % $this->itens_per_page > 0 ) $totalPaginas++;
                
                // Última Página
                if ( $primeiraPagina + 4 > $totalPaginas ){
                	$ultimaPagina = $totalPaginas;
                	$primeiraPaginaOriginal = $primeiraPagina;
                	for ( $i = 1; $i < 5 - ( $ultimaPagina - $primeiraPaginaOriginal ); $i++ )
                		if ( $primeiraPagina > 1 ) $primeiraPagina--;
                		else break;
                }
                else $ultimaPagina = $primeiraPagina + 4;
                	
                $html .= "<div class='primeiro' style ='width:20%; float:left; border:none'>&nbsp;";
                if ( $pagina > 1 ) {
                	$html .= "<a href='$url" . $separator . "pagina=1" .$urlPesquisa."'>Primeira</a>";            	
                }
                $html .= "</div>";
                
                
                $html .= "<div class='paginas' style ='width: 60%; float:left; border:none'>";
                if ( $pagina > 1 ) {
                	$html .= "<a class='anterior' href='$url" . $separator . "pagina=" . ( $pagina - 1 ) . "$urlPesquisa'>«</a>&nbsp;";
                }            	
                for ( $i = $primeiraPagina; $i <= $ultimaPagina; $i++ ){
                	
                	if ( $i > 1 ) $html .= ' | ';
                	$html .= ( $i != $pagina ) ? "<a href='$url" . $separator . "pagina=$i$urlPesquisa'>$i</a>" : '<span class="paginaAtual">'.$i.'</span>';
                	
                }
                if ( $ultimoItem < $totalItens ){
                	$html .= "&nbsp;<a class='proximo' href='$url" . $separator . "pagina=" . ( $pagina + 1 ) . "$urlPesquisa'>»</a>&nbsp;";
                }
                $html .= "</div>";
                
                
                $html .= "<div  class='ultimo' style ='width: 20%; text-align:right; float:right; border:none'>&nbsp;";
                if ( $ultimoItem < $totalItens ){
                	$html .= "<a href='$url" . $separator . "pagina=$totalPaginas$urlPesquisa'>Última</a>";
                }
                $html .= "</div>";                
                
                $html .= "</td>";
    	        $html .= "</tr>";     	
                $html .= "</tfoot>";
            }
	    }          	     
	    
        return $html;
	}
	
		
	/**
	 * Total de Colunas
	 * @return int
	 */
	public function numColumns()
	{
	    return count($this->getColumns());
	}
	
	
	/**
	 * Total de Linhas
	 * @return int
	 */
	public function numItens()
	{
	    return pg_num_rows( $this->data );
	}
	
	
	/**
	 * firstItemIndex
	 * @return int
	 */
	public function firstItemIndex()
	{
	    return ( $this->page - 1 ) * $this->itens_per_page;
	}
	
	
	
	/**
	 * lastItemIndex
	 * @return int
	 */
	public function lastItemIndex()
	{
	    if ($this->itens_per_page == -1) {
	        return $this->numItens();
	    }
	    return ( $this->page * ($this->itens_per_page) > $this->numItens() ) ? $this->numItens() : ($this->page * $this->itens_per_page);
	}
	
	
	/**
	 * setModel
	 */
	public function setModel($value)
	{
	    $this->model = $value;
	    return $this;
	}	
	
	/**
	 * getModel
	 * @return object
	 */
	public function getModel()
	{
	    return $this->model;
	}		
	
	/**
	 * setMetodo
	 */
	public function setMetodo($value)
	{
	    $this->metodo = $value;
	    return $this;
	}	
	
	/**
	 * getMetodo
	 * @return object
	 */
	public function getMetodo()
	{
	    return $this->metodo;
	}	
	
	/**
	 * Add Column
	 * @param TDataTableColumn
	 */
	public function addColumn( TDataTableColumn $column )
	{
	    if ($this->numColumns() > 0){
	        $col =  $this->columns[$this->numColumns()-1];
	        if ($col->getType() == TDataTableColumn::COLUMN_TYPE_ACTION){
	            $this->columns[] = $col;
	            $this->columns[$this->numColumns()-2] = $column;
	        }
	        else{
	            $this->columns[] = $column;
	        }
	    }else{
	        $this->columns[] = $column;
	    }	    
	    return $this;
	}
	
	/**
	 * Add Many Column
	 * @param array
	 */
	public function addManyColumns( $columns )
	{
	    foreach($columns as $col){
	        $this->addColumn($col);
	    }	    
	    return $this;
	}

	/**
	 * Add Radio Column
	 * @return TDataTableColumn
	 */
	public function addRadioColumn($atributoHtml='')
	{
	    $col = new TDataTableColumn('',TDataTableColumn::COLUMN_TYPE_RADIO);
	    $col->setAtributoHtml($atributoHtml);
	    $this->columns[] = $col;
	    return $this;
	}	
	
	/**
	 * Add Check Column
	 * @return TDataTableColumn
	 */
	public function addCheckColumn($atributoHtml='')
	{
	    $col = new TDataTableColumn('',TDataTableColumn::COLUMN_TYPE_CHECK);
	    $col->setAtributoHtml($atributoHtml);
	    $this->columns[] = $col;
	    return $this;
	}	

	/**
	 * get Column
	 * @return array
	 */
	public function getColumns()
	{
	    return $this->columns;
	}	
	
	/**
	 * setIsPaginate
	 */
	public function setIsPaginate($value)
	{
	    $this->isPaginate = $value;
	    return $this;
	}	

	/**
	 * getIsPaginate
	 * @return bool
	 */
    public function getIsPaginate()
	{
	    return $this->isPaginate;
	}	
	
	/**
	 * setKey
	 */
	public function setKeyColumn($value)
	{
	    $this->keyColumn = $value;
	    return $this;
	}
	
	/**
	 * getKey
	 * @return array
	 */
    public function getKeyColumn()
	{
	    return $this->keyColumn;
	}
	
	/**
	 * Load Data Filters
	 * @return void
	 */
	public function loadDataFilters()
	{	    
    	#Codigo de Pesquisa referente a ação do botao pesquisar
    	$formPesquisa = array();
    	if ($this->seachGrid){	
        	if (isset($_POST['btnAcao']) and ($_POST['btnAcao'] =='Pesquisar')){
        	    foreach ($_POST as $key => $value){
        	        $pesquisa = array();
        	        if (strpos($key, 'fil_') !== FALSE and (!empty($value)) ){
        	            //Quando o nome do campo tem espaços a pesquisa (POST) altera os espaços por underline, estamos voltando para espaços.
        	            $pesquisa['campo'] = str_replace('_',' ',substr($key,4,strlen($key)));
        	            $pesquisa['valor'] = $this->prepareValueFilter($pesquisa['campo'],$value);
        	            $formPesquisa[] = $pesquisa;
        	        }        
        	    }
        	}
        	else{
        	    foreach ($_GET as $key => $value){
        	        $pesquisa = array();
        	        if (strpos($key, 'fil_') !== FALSE and (!empty($value)) ){
        	            //Quando o nome do campo tem espaços a pesquisa (POST) altera os espaços por underline, estamos voltando para espaços.
        	            $pesquisa['campo'] = str_replace('_',' ',substr($key,4,strlen($key)));
        	            $pesquisa['valor'] = $this->prepareValueFilter($pesquisa['campo'],$value);
        	            $formPesquisa[] = $pesquisa;
        	        } 
        	    }
        	}
    	}
    	    	
    	$this->dataFilters = $formPesquisa;
	    
	}
	
	/**
	 * Prepara o valor digitado (selecionado) no filtro de pesquisa
	 * removendo mascaras, fazendo uppercase, etc
	 * @param $campo string
	 * @param $valor string|int
	 * @return string|int
	 */
	public function prepareValueFilter($campo,$valor)
	{
	    $valor = strtoupper($valor);
	   	foreach($this->columns as $col){	        
	        if($col->getName() == $campo){
	            if ($col->getMask() !== NULL){
	                switch($col->getMask()){
	                    case TDataTableColumn::MASK_CPF:
	                        $valor = TUtils::CpfToNum($valor);
	                        break;	                    
	                    default:
	                        break;	                        
	                }              
	            }
	            break;
	        }
	    }        	    
	    return $valor;
	}
	
	
	/**
	 * Load Page
	 */
	public function loadPageNumber()
	{
	    if (isset($_GET['pagina'])){
	        $this->page = $_GET['pagina'];
	    } else {
	        $this->page = 1;	        
	    }
	}
	
	/**
	 * Load Data
	 */
	public function loadData($model, $criteria)
	{	   
	    $this->loadCriteria($model, $criteria);
	    $metodo = $this->metodo;
	    $this->data = $this->model->$metodo($this->criteria);
	}
	
	/**
	 * Load Criteria
	 */
	public function loadCriteria($model, $criteria)
	{	    
	    $this->loadDataFilters();
	    if(!isset($criteria['precondicao'])){
	        $criteria['precondicao'] =  TSqlSelect::prepareFilterSQL($this->dataFilters,$model->getTableName());
	    }else{
	        $sql = TSqlSelect::prepareFilterSQL($this->dataFilters,$model->getTableName());
	        if (!empty($sql)){
	            $criteria['precondicao'] .= ' AND '.$sql ;
	        }	        
	    }	    
	    $this->criteria = $criteria;
	}
	
	
	public function linkColumnActionDefault()
	{
	    // Padrões
    	if ( strpos( $_SERVER['REQUEST_URI'], '?' ) > -1 ){
    		$parametroExistente = substr($_SERVER['REQUEST_URI'], strpos( $_SERVER['REQUEST_URI'], '?' ) + 1 );
    		//removendo a variavel (GET) pagina do link
            $parametroExistente = preg_replace(array ('/pagina=(\d{1,4})/','/&pagina=(\d{1,2})/'), array ('',''),$parametroExistente );
            
    		if ( strpos( $parametroExistente, '&id=' ) > -1 ){
    			$parametroExistente = substr($parametroExistente, 0, strpos( $parametroExistente, '&id=' ));
    			$linkEditarPadrao = "cadastrar.php?$parametroExistente" . "&id=";
    		}
    		else
    			$linkEditarPadrao = "cadastrar.php?$parametroExistente" . "&id=";
    	}
    	else
    		$linkEditarPadrao = 'cadastrar.php?id=';
    		
    	return $linkEditarPadrao;
	}
	
	
	public function addColumnsData($arrayColumnsName)
	{	    
	    foreach($arrayColumnsName as $col){
	        $mask = NULL;
	        if(is_string($col)){
	            $name = $col;
	            $header = $col;
	        }
	        if (is_array($col)){
	            $name = $col['name'];
	            $header = (isset($col['header'])) ? $col['header'] : $col['name'];
	            $mask = (isset($col['mask'])) ? $col['mask'] : NULL;
	        }
	        $dataType = ( isset( $this->model->columnTypes ) AND isset( $this->model->columnTypes[$name] ) ) ? $this->model->columnTypes[$name] : NULL;	        
	        $tableColumn = new TDataTableColumn($name,TDataTableColumn::COLUMN_TYPE_DATA, $header,$dataType);
	        
	        if(!is_null($mask)){
	            $tableColumn->mask = $mask;
	        }
	        
	        $this->addColumn($tableColumn);
	    }
	}
	
    public function addFiltersCombo($arrayColumnsName)
	{
	    foreach($arrayColumnsName as $col){
	        foreach($this->getColumns() as $dtcol){
	            if ($dtcol->getName() == $col){
	                $dtcol->setFilterType(TDataTableColumn::FILTER_TYPE_COMBOBOX);
	                break;
	            }
	        }	        
	    }
	}
	
	public function getDefaultEmptyMsg()
	{
	    return 'A pesquisa não retornou nenhum registro.';
	}
    
}